#pragma once


#include "lsp.h"
#include <map>
#include <queue>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>

struct lsp_server
{
	int sockfd;
	int next_connid;
	sockaddr_in me;
	std::map<int,int> seqnum;
	std::map<int,sockaddr_in> client;
	std::queue<LSPMessage> read;
	std::map< int,std::queue<LSPMessage> > to_send;
	pthread_mutex_t read_lock;
	pthread_mutex_t to_send_lock;
	pthread_mutex_t epoch_lock;
	pthread_cond_t new_msg_pushed;
	std::map<int,LSPMessage> last_sent;
	pthread_t lsp_thread;
	pthread_t epoch_thread;
	bool close_flag;
	std::map<int,int> epochs_since_contact;
	std::map<int,bool> waiting_on_ack;
	std::map<int,bool> connection_lost;
};


lsp_server* lsp_server_create(int port);
//The return value of this is what will be passed into the other functions as a_srv.
//Returns null if the create did not work


int  lsp_server_read(lsp_server* a_srv, void* pld, uint32_t* conn_id);
//a_srv is input. It will always be the same.
//pld is output. It will be a null terminated char*
//conn_id is output. It will be set based on what client the message is from.
//Returns length of pld
//Returns -1 is something went very wrong


bool lsp_server_write(lsp_server* a_srv, void* pld, int lth, uint32_t conn_id);
//a_srv is input. It will always be the same.
//pld is input. It should be a null terminated char*
//lth is input. It should be the length of pld including null character.
//conn_id is input. It determines what client to send to.
//Returns true if the write worked.
//Returns false if the connection was lost.


bool lsp_server_close(lsp_server* a_srv, uint32_t conn_id);

void lsp_server_send_last(lsp_server* srv, int connid);
void *lsp_server_lsp_thread(void *a_srv);
void *lsp_server_epoch_thread(void *a_srv);